package com.erli.exchange.common.sg;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

import com.erli.exchange.common.sg.config.MapperXmlInfo;
import com.erli.exchange.common.sg.entity.FieldInfo;
import com.erli.exchange.common.sg.mapper.If;
import com.erli.exchange.common.sg.mapper.Include;
import com.erli.exchange.common.sg.mapper.Insert;
import com.erli.exchange.common.sg.mapper.Mapper;
import com.erli.exchange.common.sg.mapper.ResultMap;
import com.erli.exchange.common.sg.mapper.ResultMapId;
import com.erli.exchange.common.sg.mapper.ResultMapResult;
import com.erli.exchange.common.sg.mapper.SQL;
import com.erli.exchange.common.sg.mapper.Select;
import com.erli.exchange.common.sg.mapper.Set;
import com.erli.exchange.common.sg.mapper.Trim;
import com.erli.exchange.common.sg.mapper.Update;
import com.erli.exchange.common.sg.mapper.Where;
import com.erli.exchange.core.util.JAXBUtil;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * Mapper XML生成器
 * 
 * @title MapperXmlGenerator.java
 * @package com.example.demo.sourcegenerate
 * @author lihu
 * @update 2019年3月8日 下午3:12:33
 */
@Slf4j
public class MapperXmlGenerator extends EntitySourceGenerater {

	private final String xmlFirstLineReplace = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
	private final String xmlFirstLine = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
	private final String doctypeLine = "<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >";

	private final MapperXmlInfo mapperXmlInfo = this.getGenerateConfig().getMapperxml();

	@Override
	public void generateSourceFile(String tableName) throws Exception {
		List<FieldInfo> fieldList = this.getFieldList(tableName);
		Mapper mapper = getMapperObj(fieldList);
		String xmlFileName = getClassNameByBaseClassInfo(mapperClassInfo).concat(baseInfo.getXmlFileSuffix());
		writeToXMLFile(JAXBUtil.toXML(mapper),
				getMapperXmlOutPutDir(mapperXmlInfo.getResourcesFileLocation()), xmlFileName,
				mapperXmlInfo.isFileExistsDelete());
		log.info("done!");
	}

	/**
	 * 获取XML输出路径
	 * 
	 * @param subDir
	 * @return
	 * @author lihu
	 * @update 2019年3月8日 下午3:10:37
	 */

	private String getMapperXmlOutPutDir(String subDir) {
		String projectLocation = baseInfo.getProjectLocation();
		String resourcesLocation = baseInfo.getResourcesFileLocation();
		String module = getSelfClassInfo().getModule();
		return new StringBuilder().append(projectLocation).append(module).append(SLASH).append(resourcesLocation).append(subDir).toString();
	}

	/**
	 * mapper的XML文件
	 * 
	 * @param xmlContent
	 * @param output
	 * @param xmlFileName
	 * @param fileExistsDelete
	 * @throws IOException
	 * @author lihu
	 * @update 2019年3月8日 下午3:10:16
	 */
	private void writeToXMLFile(String xmlContent, String output, String xmlFileName, boolean fileExistsDelete)
			throws IOException {
		File outputDir = new File(output);
		if (!outputDir.exists()) {
			outputDir.mkdirs();
		}

		File file = new File(output, xmlFileName);
		if (file.exists()) {
			if (fileExistsDelete) {
				file.delete();
			} else {
				log.info(String.format("文件【%s】已经存在", file.getName()));
				return;
			}
		}

		BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(new FileOutputStream(new File(output, xmlFileName))));
		try {
			bw.write(xmlFirstLine);
			bw.write(LF);
			bw.write(doctypeLine);
			bw.write(xmlContent.replace(xmlFirstLineReplace, ""));
			bw.write(LF);
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
			log.info(e.getMessage());
		}
	}

	/**
	 * 获取Mapper对象
	 * 
	 * @param fieldList
	 * @return
	 * @author lihu
	 * @update 2019年2月20日 下午2:49:57
	 */
	private Mapper getMapperObj(List<FieldInfo> fieldList) {
		Mapper mapper = new Mapper();
		mapper.setNamespace(getFullClassPathByBaseClassInfo(mapperClassInfo));
		mapper.setResultMapList(getResultMapListData(fieldList));
		mapper.setSqlList(getSQListData(fieldList));
		//		mapper.setInsertList(getInsertListData(fieldList));
		//		mapper.setSelectList(getSelectListData(fieldList));
		//		mapper.setUpdateList(getUpdateListData(fieldList));
		return mapper;
	}

	/**
	 * ResultMap
	 * 
	 * @param fieldList
	 * @return
	 * @author lihu
	 * @update 2019年2月20日 下午2:44:33
	 */
	private List<ResultMap> getResultMapListData(List<FieldInfo> fieldList) {
		List<ResultMap> data = new ArrayList<>();
		ResultMap resultMap = new ResultMap();
		// ID写死
		resultMap.setId("BaseResultMap");
		resultMap.setType(getFullClassName());

		List<ResultMapResult> resultMapResultList = new ArrayList<ResultMapResult>();
		for (FieldInfo item : fieldList) {
			if (item.isPrimaryId()) {
				ResultMapId resultMapId = new ResultMapId();
				resultMapId.setColumn("id");
				resultMapId.setJdbcType("INTEGER");
				resultMapId.setProperty("id");
				resultMap.setResultMapId(resultMapId);
			} else {
				ResultMapResult resultMapResult = new ResultMapResult();
				resultMapResult.setColumn(item.getColumnField());
				resultMapResult.setJdbcType(item.getJdbcType());
				resultMapResult.setProperty(item.getPropertyName());
				resultMapResultList.add(resultMapResult);
			}
		}
		resultMap.setResultMapResultList(resultMapResultList);
		data.add(resultMap);
		return data;
	}

	/**
	 * SQL 片段
	 * 
	 * @param fieldList
	 * @return
	 * @author lihu
	 * @update 2019年2月20日 下午2:44:18
	 */
	private List<SQL> getSQListData(List<FieldInfo> fieldList) {
		List<SQL> data = new ArrayList<>();
		SQL sql1 = new SQL();
		sql1.setId("BASE_TABLE");
		sql1.setValue(DOUBLE_TAB_NEW_LINE.concat(this.tableNameThreadLocal.get()).concat(TAB_NEW_LINE));
		SQL sql2 = new SQL();
		sql2.setId("BASE_COLUMN");
		StringBuilder stringBuilder = new StringBuilder();
		fieldList.forEach(item -> {
			stringBuilder.append(item.getColumnField()).append(COMMA);
			;
		});
		sql2.setValue(
				DOUBLE_TAB_NEW_LINE.concat(StrUtil.removeSuffix(stringBuilder.toString(), COMMA)).concat(TAB_NEW_LINE));
		data.add(sql1);
		data.add(sql2);
		return data;
	}

	/**
	 * 新增
	 * 
	 * @param fieldList
	 * @return
	 * @author lihu
	 * @update 2019年2月20日 下午2:44:07
	 */
	@SuppressWarnings("unused")
	private List<Insert> getInsertListData(List<FieldInfo> fieldList) {
		List<Insert> data = new ArrayList<>();
		Insert insert = new Insert();
		insert.setId("insert");
		insert.setUseGeneratedKeys("true");
		insert.setKeyProperty("id");

		List<Object> list = new ArrayList<Object>();

		List<If> ifList1 = new ArrayList<>();
		List<If> ifList2 = new ArrayList<>();
		for (FieldInfo item : fieldList) {
			if (item.isPrimaryId()) {
				continue;
			}
			ifList1.add(
					new If(String.format("%s != null and %s != '' ", item.getPropertyName(), item.getPropertyName()),
							item.getColumnField() + ","));
			ifList2.add(
					new If(String.format("%s != null and %s != '' ", item.getPropertyName(), item.getPropertyName()),
							String.format("#{%s},", item.getPropertyName())));
		}

		list.add("\n\t\tinsert into");
		list.add(new Include("BASE_TABLE"));
		list.add(new Trim("(", ")", ",", ifList1));
		list.add("\n\t\tvalues");
		list.add(new Trim("(", ")", ",", ifList2));
		insert.setList(list);

		data.add(insert);
		return data;
	}

	/**
	 * 更新
	 * 
	 * @param fieldList
	 * @return
	 * @author lihu
	 * @update 2019年2月20日 下午4:35:49
	 */
	@SuppressWarnings("unused")
	private List<Update> getUpdateListData(List<FieldInfo> fieldList) {
		List<Update> data = new ArrayList<>();
		List<If> ifList = new ArrayList<If>();
		for (FieldInfo item : fieldList) {
			if (item.isPrimaryId()) {
				continue;
			}
			ifList.add(new If(String.format("%s != null and %s != '' ", item.getPropertyName(), item.getPropertyName()),
					String.format("%s=#{%s},", item.getColumnField(), item.getPropertyName())));
		}

		List<Object> list = new ArrayList<>();
		list.add(DOUBLE_TAB_NEW_LINE.concat("update"));
		list.add(new Include("BASE_TABLE"));
		list.add(new Set(ifList));
		list.add(DOUBLE_TAB_NEW_LINE.concat("where id=#{id}"));
		Update update = new Update("updateByEntity", getFullClassPathByBaseClassInfo(entityClassInfo), list);
		data.add(update);
		return data;
	}

	/**
	 * 查询模版
	 * 
	 * @param fieldList
	 * @return
	 * @author lihu
	 * @update 2019年2月20日 下午2:43:55
	 */
	@SuppressWarnings("unused")
	private List<Select> getSelectListData(List<FieldInfo> fieldList) {
		List<Select> data = new ArrayList<>();

		Select select = new Select();
		select.setId("selectByEntity");
		select.setParameterType(getFullClassName());
		select.setResultMap("BaseResultMap");

		List<Object> list = new ArrayList<Object>();
		list.add(DOUBLE_TAB_NEW_LINE.concat("select"));
		list.add(new Include("BASE_COLUMN"));
		list.add(DOUBLE_TAB_NEW_LINE.concat("FROM"));
		list.add(new Include("BASE_TABLE"));

		List<If> ifList = new ArrayList<>();
		for (FieldInfo item : fieldList) {
			ifList.add(new If(String.format("%s != null and %s != '' ", item.getPropertyName(), item.getPropertyName()),
					String.format("and %s = #{%s}", item.getColumnField(), item.getPropertyName())));
		}

		list.add(new Where(ifList));
		select.setList(list);
		data.add(select);
		return data;
	}

}
